﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using LINQPad.Extensibility.DataContext;
using LINQPad.OpenAccess.Helpers;
using LINQPad.OpenAccess.Services;
using LINQPad.OpenAccess.Settings;
using LINQPad.OpenAccess.UI.Adapters;
using LINQPad.OpenAccess.UI.View;
using LINQPad.OpenAccess.UI.ViewModel;

namespace LINQPad.OpenAccess.UI.Services
{
    /// <summary>
    ///   <see cref="IDataContextUserInteractionService" />
    /// </summary>
    public class DataContextUserInteractionService : IDataContextUserInteractionService
    {
        #region Private

        #region - Vars

        [DebuggerBrowsable( DebuggerBrowsableState.Never )]
        private readonly DriverSettingsViewModel _driverSettingsViewModel;

        #endregion

        #region - Functions

        /// <summary>
        /// Builds a relative pack URI for the local resource.
        /// </summary>
        /// <param name="localResource">The local resource.</param>
        /// <returns>
        /// The pack uri.
        /// </returns>
        Uri BuildRelativePackUriForLocalResource( string localResource )
        {
            Guard.ArgumentNotNull( localResource, "localResource" );
            var assemblyName = typeof( DataContextUserInteractionService ).Assembly.GetName( ).Name;
            return new Uri
                    (
                        String.Format
                                (
                                    "/{0};component/{1}", assemblyName, localResource
                                )
                        , UriKind.Relative
                    );
        }
        /// <summary>
        /// Merges the resources.
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="resourceUri">The resource URI.</param>
        private void MergeResources( ResourceDictionary target, Uri resourceUri )
        {
            Guard.ArgumentNotNull( target, "target" );
            Guard.ArgumentNotNull( resourceUri, "resourceUri" );

            var resources = Application.LoadComponent( resourceUri ) as ResourceDictionary;
            if ( resources != null )
                target.MergedDictionaries.Add( resources );
        }

        #endregion

        #endregion

        #region Protected

        #region - Functions

        /// <summary>
        /// Creates the dialog window.
        /// </summary>
        /// <param name="windowTitle">The window title.</param>
        /// <param name="windowIcon">The window icon.</param>
        /// <returns>
        /// The dialog window.
        /// </returns>
        protected virtual Window CreateDialogWindow( string windowTitle, ImageSource windowIcon = null )
        {
            var window = new Window( )
                    {
                        WindowStartupLocation = WindowStartupLocation.CenterScreen,
                        Title = windowTitle,
                        Icon = windowIcon ?? this.GetDefaultWindowIcon( ),
                        WindowState = WindowState.Normal,
                        WindowStyle = WindowStyle.SingleBorderWindow,
                        ResizeMode = ResizeMode.CanResizeWithGrip,
                        SizeToContent = SizeToContent.Manual,
                        ShowInTaskbar = true,
                        AllowsTransparency = false,
                        Width = 700,
                        Height = 450,
                        MinWidth = 700,
                        MinHeight = 450
                    };

            var commonStylesUri = this.BuildRelativePackUriForLocalResource( "Themes/CommonStyles.xaml" );
            this.MergeResources( window.Resources, commonStylesUri );

            return window;
        }
        /// <summary>
        /// Creates the driver settings view.
        /// </summary>
        /// <returns>
        /// The view.
        /// </returns>
        protected virtual DriverSettingsView CreateDriverSettingsView( )
        {
            return new DriverSettingsView( );
        }
        /// <summary>
        /// Gets the default window icon.
        /// </summary>
        /// <returns>The icon.</returns>
        protected virtual ImageSource GetDefaultWindowIcon( )
        {
            return new BitmapImage( new Uri( "pack://application:,,,/LINQPad.OpenAccess.UI;component/Images/Settings.ico" ) );
        }

        #endregion

        #endregion

        #region Public

        #region - Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="DataContextUserInteractionService" /> class.
        /// </summary>
        /// <param name="assemblyParser">The assembly parser.</param>
        /// <param name="userInteractionService">The user interaction service.</param>
        public DataContextUserInteractionService( DriverSettingsViewModel driverSettingsViewModel )
        {
            Guard.ArgumentNotNull( driverSettingsViewModel, "driverSettingsViewModel" );
            this._driverSettingsViewModel = driverSettingsViewModel;
        }

        #endregion

        #endregion

        #region IDataContextUserInteractionService Members

        /// <summary>
        /// Edits the configuration.
        /// </summary>
        /// <param name="connectionInfo">The connection info.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>
        ///   <c>true</c> on success; otherwise, <c>false</c>.
        /// </returns>
        public bool EditConfiguration( IConnectionInfo connectionInfo, DriverSettings settings )
        {
            Guard.ArgumentNotNull( connectionInfo, "connectionInfo" );
            Guard.ArgumentNotNull( settings, "settings" );

            var window = this.CreateDialogWindow( "OpenAccess ORM Configuration" );
            var view = this.CreateDriverSettingsView( );

            this._driverSettingsViewModel.TryLoadSettingsFrom( connectionInfo, settings );

            window.Content = view;
            using ( new WindowAdapter( window, this._driverSettingsViewModel ) )
                if ( window.ShowDialog( ).GetValueOrDefault( ) )
                {
                    this._driverSettingsViewModel.WriteSettingsTo( connectionInfo, settings );
                    return true;
                }

            return false;
        }

        #endregion
    }
}
